/**
 * Memory management utilities for handling large images
 */

/**
 * Check if browser has enough memory for operation
 * @param requiredBytes Estimated bytes required
 * @returns True if enough memory is available
 */
export function checkMemoryAvailability(requiredBytes: number): boolean {
  // Check if performance.memory is available (Chrome only)
  if ('performance' in window && 'memory' in performance) {
    const memory = (performance as any).memory;
    if (memory && memory.jsHeapSizeLimit) {
      // Leave 20% buffer for other operations
      const availableMemory = memory.jsHeapSizeLimit * 0.8;
      return requiredBytes < availableMemory;
    }
  }
  
  // If we can't check memory, assume it's enough
  // but warn if the required memory is very large
  if (requiredBytes > 500 * 1024 * 1024) { // 500MB
    console.warn('Operation requires significant memory:', requiredBytes / (1024 * 1024), 'MB');
  }
  
  return true;
}

/**
 * Estimate memory required for canvas operation
 * @param width Canvas width
 * @param height Canvas height
 * @returns Estimated bytes required
 */
export function estimateCanvasMemory(width: number, height: number): number {
  // Each pixel uses 4 bytes (RGBA)
  // Add 50% overhead for canvas operations
  return width * height * 4 * 1.5;
}

/**
 * Release memory by triggering garbage collection
 * This is just a hint, not guaranteed to work
 */
export function releaseMemory(): void {
  // Set large objects to null
  const largeArrays: any[] = [];
  for (let i = 0; i < 10; i++) {
    largeArrays.push(new Array(1000000).fill(0));
  }
  
  // Clear the arrays
  for (let i = 0; i < largeArrays.length; i++) {
    largeArrays[i] = null;
  }
  
  // Force a minor GC
  for (let i = 0; i < 10; i++) {
    const array = new Array(1000000).fill(0);
    array.length = 0;
  }
}

/**
 * Process images in batches to avoid memory issues
 * @param items Items to process
 * @param batchSize Number of items to process in each batch
 * @param processFn Function to process each item
 * @param onProgress Optional callback for progress updates
 * @returns Promise with array of processed items
 */
export async function processBatch<T, R>(
  items: T[],
  batchSize: number,
  processFn: (item: T) => Promise<R | null>,
  onProgress?: (progress: number) => void
): Promise<R[]> {
  const results: R[] = [];
  const totalItems = items.length;
  let processedItems = 0;
  
  // Process items in batches
  for (let i = 0; i < totalItems; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    const batchPromises = batch.map(async (item) => {
      try {
        return await processFn(item);
      } catch (error) {
        console.error('Processing item failed:', error);
        return null;
      }
    });
    
    // Wait for all items in the batch to be processed
    const batchResults = await Promise.all(batchPromises);
    
    // Filter out null results and add to results
    batchResults.forEach(result => {
      if (result !== null) {
        results.push(result);
      }
    });
    
    // Update progress
    processedItems += batch.length;
    if (onProgress) {
      onProgress(Math.round((processedItems / totalItems) * 100));
    }
    
    // Give the browser a chance to update the UI and garbage collect
    await new Promise(resolve => setTimeout(resolve, 0));
  }
  
  return results;
}